package DataModel.ConnectivityManager;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import DataModel.CommonLibrary.CommonDefs.Layer;
import DataModel.LayoutManager.CRectangle;
import ScanLineAlghorithms.RectanglesIntersection;

public class CConnectivityManager 
{
	/***************************************************/
	/****** C'tors *************************************/
	/***************************************************/
	public CConnectivityManager(LinkedList<CRectangle> recsList) 
	{
		Initialize(recsList);
	}
	
	
	/***************************************************/
	/****** Members ************************************/
	/***************************************************/
	private CRectangleConnectivityGraph m_recsGraph;
	
	
	/***************************************************/
	/****** Getters / Setters **************************/
	/***************************************************/
	public CRectangleConnectivityGraph getRecsGraph() {
		return m_recsGraph;
	}


	public void setRecsGraph(CRectangleConnectivityGraph graph) {
		m_recsGraph = graph;
	}

	
	/***************************************************/
	/****** Public Functions ***************************/
	/***************************************************/
	public boolean AreConnected(long id1, long id2)
	{
		return m_recsGraph.AreConnected(id1, id2);
	}
	
	/***************************************************/
	/****** Utils **************************************/
	/***************************************************/
	private void Initialize(LinkedList<CRectangle> recsList)
	{
		m_recsGraph = new CRectangleConnectivityGraph(recsList);
		/* 
		 * Create temporary data structure:
		 * Array in the size of all layers (including connectors)
		 */
		int tempArrSize = Layer.values().length; 
		
		ArrayList<LinkedList<CRectangle>> recsByLayers = 
			new ArrayList<LinkedList<CRectangle>>(tempArrSize);
		
		for(int i=0; i<tempArrSize; ++i){
			recsByLayers.add(i, new LinkedList<CRectangle>());
		}
		
		// Sort rectangles by layer and fill temporary structure
		for (CRectangle rectangle : recsList) 
		{
			recsByLayers.get(rectangle.getLayer().ordinal()).add(rectangle);
		}
		 
		RunLayersIntersect(Layer.N_diff.ordinal(), Layer.Contact.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.P_diff.ordinal(), Layer.Contact.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Poly.ordinal(), Layer.Contact.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal1.ordinal(), Layer.Contact.ordinal(), recsByLayers);		

		RunLayersIntersect(Layer.Metal1.ordinal(), Layer.Via1_2.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal2.ordinal(), Layer.Via1_2.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal2.ordinal(), Layer.Via2_3.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal3.ordinal(), Layer.Via2_3.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal3.ordinal(), Layer.Via3_4.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal4.ordinal(), Layer.Via3_4.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal4.ordinal(), Layer.Via4_5.ordinal(), recsByLayers);
		RunLayersIntersect(Layer.Metal5.ordinal(), Layer.Via4_5.ordinal(), recsByLayers);
		
		m_recsGraph.RunUnionFind();
	}
	
	/*
	 * Run intersection algorithm on each layer & connectors and add
	 * all pairs to connectivity graph
	 * Starting with Poly layer
	 */
	private void RunLayersIntersect(int layer1, int layer2, ArrayList<LinkedList<CRectangle>> recsByLayers)
	{
		// Create input & output structures for the algorithm
		LinkedList<CRectangle> inputList = 
			new LinkedList<CRectangle>();
		Hashtable<Long, LinkedList<CRectangle>> outputTable =
			new Hashtable<Long, LinkedList<CRectangle>>();
		
		// Fill input structure
		inputList.addAll(recsByLayers.get(layer1));
		inputList.addAll(recsByLayers.get(layer2));
		
		if(inputList.size() > 0)
		{
			// Run algorithm
			RectanglesIntersection.Activate(inputList, outputTable);
			
			// Add output table to graph
			m_recsGraph.AddToGraph(outputTable);
		}
	}
}
